package com.fishery.customization.dao;

import com.fishery.customization.dao.reposity.BaseDao;
import com.fishery.customization.entity.Label;
import com.fishery.customization.entity.OneLevelLabel;
import com.fishery.customization.util.DataUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Repository
public class LabelDao extends BaseDao<Label> {

	@Autowired
	private MongoOperations mongoOperations;

	/**
	 * 以JSON格式通过基地id、角色查出标签
	 *
	 * @param baseId
	 * @param role
	 * @return
	 */
	public String findLabelJsonByBaseIdAndRole(String baseId, String role) {
		Map<String, Object> queryMap = new HashMap<>(2);
		Map<String, Object> fieldsMap = new HashMap<>(2);
		queryMap.put("base_id", baseId);
		queryMap.put("role", role);
		fieldsMap.put("labels", 1);
		fieldsMap.put("_id", 0);
		return mongoOperations.findOne(getBasicQuery(queryMap, fieldsMap),
				String.class, getCollectionName());
	}

	/**
	 * 以对象格式通过基地id、角色查出标签
	 *
	 * @param baseId
	 * @param role
	 * @return
	 */
	public Label findLabelByBaseIdAndRole(String baseId, String role) {
		Label label = new Label();
		label.setBaseId(baseId);
		label.setRole(role);
		return findOne(Example.of(label)).get();
	}


	/**
	 * 先查后修改策略(有做去重处理)
	 *
	 * @param baseId
	 * @param role
	 * @param addOneLevelLabels
	 * @param deleteOneLevelLabels
	 * @return
	 */
	public long queryAndUpdate(String baseId, String role, Collection<OneLevelLabel> addOneLevelLabels,
							   Collection<OneLevelLabel> deleteOneLevelLabels) {
		if ((addOneLevelLabels == null || addOneLevelLabels.isEmpty())
				&& (deleteOneLevelLabels == null || deleteOneLevelLabels.isEmpty())) {
			return 1;
		}
		// 查询mongo里面原本该基地角色对应的标签对象
		Label oldLabel = findLabelByBaseIdAndRole(baseId, role);
		// 查询所有原先的一级标签集合
		List<OneLevelLabel> oldOneLevelLabels = oldLabel.getLabels();
		// 在原先的基础上删除二级标签
		if (deleteOneLevelLabels != null && !deleteOneLevelLabels.isEmpty()) {
			DataUtil.exceptSameLabels(deleteOneLevelLabels, oldOneLevelLabels);
		}
		// 在原先的基础上去增加二级标签
		if (addOneLevelLabels != null && !addOneLevelLabels.isEmpty()) {
			addOneLevelLabels.forEach(oneLevelLabel -> {
				AtomicBoolean flag = new AtomicBoolean(false);
				oldOneLevelLabels.forEach(oldOneLevelLabel -> {
					if (flag.get() || oneLevelLabel.getChildren().isEmpty()) {
						return;
					}
					if (oneLevelLabel.getName().equals(oldOneLevelLabel.getName())) {
						oldOneLevelLabel.getChildren().addAll(oneLevelLabel.getChildren());
						flag.compareAndSet(false, true);
					}
				});
				if (!flag.get() && !oneLevelLabel.getChildren().isEmpty()) {
					oldOneLevelLabels.add(oneLevelLabel);
				}
			});
		}
		return mongoOperations.updateFirst(Query.query(Criteria.where(getIdName())
						.is(getIdValue(oldLabel))), Update.update("labels", oldOneLevelLabels),
				Label.class, getCollectionName()).getModifiedCount();
	}

	/**
	 * 对该基地角色进行拓展标签
	 *
	 * @param baseId
	 * @param role
	 * @param extendLabels
	 * @return
	 */
	public long extend(String baseId, String role, Collection<OneLevelLabel> extendLabels) {
		return queryAndUpdate(baseId, role, extendLabels, null);
	}

	/**
	 * 通过基地id查询基地类型
	 *
	 * @param baseId
	 * @return
	 */
	public List<String> findTypesByBaseId(String baseId) {
		Map<String, Object> fieldsMap = new HashMap<>(2);
		fieldsMap.put("base_type", 1);
		fieldsMap.put("_id", 0);
		return mongoOperations.findOne(getBasicQuery("base_id", baseId, fieldsMap),
				Label.class, getCollectionName()).getBaseType();
	}

	private void update(Map<String, Object> queryMap, OneLevelLabel label) {
		try {
			mongoOperations.upsert(getBasicQuery(queryMap),
					Update.update("labels.$.children", label.getChildren()), getCollectionName());
		} catch (Exception e) {
			// 标签原先不存在,进行保存
			queryMap.remove("labels.name");
			mongoOperations.upsert(getBasicQuery(queryMap), new Update().push("labels", label),
					getCollectionName());
		}
	}

	/**
	 * 除了该角色的基地所有角色进行拓展标签
	 *
	 * @param baseId
	 * @param role
	 * @param extendLabels
	 * @return
	 */
	public long extendExceptThisRole(String baseId, String role, List<OneLevelLabel> extendLabels) {
		List<String> otherRoles = mongoOperations.find(getBasicQuery("base_id", baseId)
				.addCriteria(Criteria.where("role").nin(role)), String.class, getCollectionName());
		if (otherRoles != null && !otherRoles.isEmpty()) {
			otherRoles.forEach(oRole -> queryAndUpdate(baseId, oRole,
					extendLabels, null));
		}
		return 1;
	}

	/**
	 * 更新基地类型
	 *
	 * @param baseId
	 */
	public long updateTypesOfBase(String baseId, List<String> types) {
		List<String> baseTypes = findTypesByBaseId(baseId);
		baseTypes.addAll(types);
		return mongoOperations.updateMulti(Query.query(Criteria.where("base_id").is(baseId))
				, Update.update("base_type", baseTypes), getCollectionName()).getModifiedCount();
	}

	/**
	 * 通过基地ID修改基地角色名
	 *
	 * @param baseId
	 * @param oldName
	 * @param newName
	 * @return
	 */
	public long updateBaseRoleNameByBaseId(String baseId, String oldName, String newName) {
		Map<String, Object> queryMap = new HashMap<>(2);
		queryMap.put("base_id", baseId);
		queryMap.put("role", oldName);
		return mongoOperations.updateFirst(getBasicQuery(queryMap),
				Update.update("role", newName), getCollectionName()).getModifiedCount();
	}

	/**
	 * 通过基地Id和排除的角色，查出基地其它角色
	 *
	 * @param baseId
	 * @param exceptRole
	 * @return
	 */
	public List<String> findOtherRoles(String baseId, String exceptRole) {
		Map<String, Object> fieldsMap = new HashMap<>(2);
		fieldsMap.put("_id", 0);
		fieldsMap.put("role", 1);
		return mongoOperations.find(getBasicQuery("base_id", baseId, fieldsMap)
				.addCriteria(Criteria.where("role").ne(exceptRole)), String.class, getCollectionName());
	}
}
